//
//  ZYUrlSessionManagerTaskDelegate.m
//  ZYWebImage
//
//  Created by wangzhipan on 2025/4/14.
//

#import "ZYUrlSessionManagerTaskDelegate.h"
#import "ZYUrlSessionManager.h"
#import <objc/runtime.h>



@interface ZYUrlSessionManagerTaskDelegate()
@property (nonatomic, weak) ZYUrlSessionManager *sessionMgr;
@property (nonatomic, strong, nullable, readwrite) NSURLSessionTaskMetrics *taskMetrics;
@property (nonatomic, strong, nullable) NSMutableData *mutableData;


@property (nonatomic, assign) NSUInteger currentSentSize;
@property (nonatomic, assign) NSUInteger totalSize;
@end

@implementation ZYUrlSessionManagerTaskDelegate

static dispatch_queue_t url_session_manager_processing_queue(void) 
{
    static dispatch_queue_t queue;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        queue = dispatch_queue_create("com.url_session_manager_processing_queue.ZYUrlSessionManagerTaskDelegate", DISPATCH_QUEUE_CONCURRENT);
    });
    return queue;
}

- (instancetype)initWithSessionManager:(ZYUrlSessionManager *)sessionManager
{
    if (self = [super init]) {
        self.sessionMgr = sessionManager;
        
        self.mutableData = [NSMutableData data];
        self.currentSentSize = 0;
        self.totalSize = 0;
    }
    return self;
}

#pragma mark - NSURLSessionTaskDelegate
/* Sent periodically to notify the delegate of upload progress.  This
 * information is also available as properties of the task.
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
                                didSendBodyData:(int64_t)bytesSent
                                 totalBytesSent:(int64_t)totalBytesSent
                       totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
{
    self.totalSize = totalBytesExpectedToSend;
    self.currentSentSize = totalBytesSent;
}


/*
 * Sent when complete statistics information has been collected for the task.
 */
- (void)URLSession:(NSURLSession *)session 
              task:(NSURLSessionTask *)task
didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0))
{
    self.taskMetrics = metrics;
}

/* Sent as the last message related to a specific task.  Error may be
 * nil, which implies that no error occurred and this task is complete.
 */
- (void)URLSession:(NSURLSession *)session 
              task:(NSURLSessionTask *)task
didCompleteWithError:(nullable NSError *)error
{
    //取出tsl\ssl验证错误信息
    error = objc_getAssociatedObject(task, &kAuthenticationChallengeErrorKey) ?: error;
    
    __strong ZYUrlSessionManager *manager = self.sessionMgr;
    __block id responseObject = nil;
    
    NSData *data = nil;
    if (self.mutableData) {
        data = [self.mutableData copy];
        self.mutableData = nil;
    }
    
    if (error) {
        dispatch_async(dispatch_get_main_queue(), ^{
            self.completedBlock ? self.completedBlock(task.response, responseObject, error) : nil;
        });
    }
    else {
        //子线程解析数据
        dispatch_async(url_session_manager_processing_queue(), ^{
            NSError *serializationError = nil;
            responseObject = [manager.responseSerializer responseObjectForResponse:task.response
                                                                              data:data
                                                                             error:&serializationError];
            dispatch_async(dispatch_get_main_queue(), ^{
                self.completedBlock ? self.completedBlock(task.response, responseObject, serializationError) : nil;
            });
        });
    }
}

#pragma mark - NSURLSessionDataDelegate
- (void)URLSession:(NSURLSession *)session 
          dataTask:(NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data
{
    [self.mutableData appendData:data];
}

#pragma mark - getter && setter
- (void)setCurrentSentSize:(NSUInteger)currentSentSize
{
    _currentSentSize = currentSentSize;
    self.uploadProgress ? self.uploadProgress(_currentSentSize, _totalSize) : nil;
}

- (void)setTotalSize:(NSUInteger)totalSize
{
    _totalSize = totalSize;
    self.uploadProgress ? self.uploadProgress(_currentSentSize, _totalSize) : nil;
}
@end
